package mqq.model;

import java.util.ArrayList;
import java.util.List;

/**
 * Entity object of a Decision Lines Event
 * @author mqq
 */
public class DecisionLinesEvent {
	/** Number of rounds in this event */
	int numRounds;

	/** Number of lines/choices in this event */
	int numLines;
	
	/** All the lines in this event */
	public List<Line> lines = new ArrayList<Line>();
	
	/**
	 * Constructor
	 * All the lines are created here
	 * @param numRounds  Number of rounds in this event
	 * @param numLines  Number of lines/choices in this event
	 */
	public DecisionLinesEvent(int numRounds, int numLines) {
		this.numRounds = numRounds;
		this.numLines = numLines;
		for (int i = 0; i < numLines; i++) {
			this.lines.add(new Line(i));
		}
	}
	
	/**
	 * Determine the priority based on the edges
	 * @return  List of string representing the prioritized list of choices
	 */
	public String[] prioritizedChoices() {
		String[] result = new String[numLines];
		for (int i = 0; i < this.numLines; i++) {
			int currentPosition = i;
			Line currentLine = this.lines.get(currentPosition);
			int currentHeight = -1;
			while (currentLine.nextEdge(currentHeight) != null) {
				if (currentPosition == currentLine.nextEdge(currentHeight).left) {
					currentPosition++;
				} else {
					currentPosition--;
				}
				currentHeight = currentLine.nextEdge(currentHeight).height;
				currentLine = this.lines.get(currentPosition);
			}
			result[currentPosition] = this.lines.get(i).choice;
		}
		return result;
	}
	
	/**
	 * Determines whether the edge is valid
	 * @param e  The edge to be determined
	 * @return  true if valid; false if not
	 */
	public boolean isValidEdge(Edge e) {
		Line leftLine = this.lines.get(e.left);
		int numEdgesLeft = leftLine.edges.size();
		for (int i = 0; i < numEdgesLeft; i++) {
			int diff = leftLine.edges.get(i).height - e.height;
			if (diff <= 7 && diff >= -7) {
				return false;
			}
		}
		Line rightLine = this.lines.get(e.right);
		int numEdgesRight = rightLine.edges.size();
		for (int i = 0; i < numEdgesRight; i++) {
			int diff = rightLine.edges.get(i).height - e.height;
			if (diff < 8 && diff > -8) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Associate an edge with appropriate lines
	 * @param e  The edge to be added
	 * @return  true if edge successfully added; false otherwise
	 */
	public boolean addEdge(Edge e) {
		if (!this.isValidEdge(e)) {
			return false;
		} else {
			this.lines.get(e.left).edges.add(e);
			this.lines.get(e.right).edges.add(e);
			return true;
		}
	}
	
	/**
	 * Set the choice of a certain line
	 * @param position  The position of the line wanted
	 * @param value  The new choice to be set
	 * @return  true if successful; false if not
	 */
	public boolean setChoice(int position, String value) {
		if (value.length() == 0) {
			return false;
		}
		for (int i = 0; i < this.numLines; i++) {
			if (this.lines.get(i).choice.equals(value) && i != position) {
				return false;
			}
		}
		this.lines.get(position).setChoice(value);
		return true;
	}
	
	/**
	 * Determine whether the program is done
	 * @return  true if yes; false if not
	 */
	public boolean isDone() {
		int counter = 0;
		for (int i = 0; i < this.numLines; i++) {
			counter = counter + this.lines.get(i).edges.size();
		}
		if (counter == numLines * numRounds * 2) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Determine whether each choice blank is filled
	 * @return  true if all filled; false, otherwise 
	 */
	public boolean isReady() {
		for (int i = 0; i < this.numLines; i++) {
			if (this.lines.get(i).choice.length() == 0) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Get the number of lines
	 * @return  The number of lines
	 */
	public int getNumLines() {
		return this.numLines;
	}
}
